package com.glodon.paas.account.security.oauth2.controller;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.glodon.paas.account.security.spring.LoginUser;


/**
 * @author Don Li
 */
@Controller
public class CheckTokenService {

    @Autowired
    private ResourceServerTokenServices resourceServerTokenServices;

    @RequestMapping(value = "/oauth2/check_token", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, ?> checkToken(@RequestParam("token") String value) {
        OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
        if (token == null) {
            throw new InvalidTokenException("Token was not recognised");
        }
        if (token.isExpired()) {
            throw new InvalidTokenException("Token has expired");
        }
        OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(value);
        Map<String, ?> response = convertAccessToken(token, authentication);
        return response;
    }

    public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        Map<String, Object> response = new HashMap<String, Object>();
        AuthorizationRequest clientToken = authentication.getAuthorizationRequest();

        if (!authentication.isClientOnly()) {
            response.putAll(convertUserAuthentication(authentication.getUserAuthentication()));
        }

        response.put(OAuth2AccessToken.SCOPE, token.getScope());
        if (token.getExpiration() != null) {
            response.put("exp", token.getExpiration().getTime() / 1000);
        }

        response.putAll(token.getAdditionalInformation());

        response.put("client_id", clientToken.getClientId());
        if (clientToken.getResourceIds() != null && !clientToken.getResourceIds().isEmpty()) {
            response.put("resource_ids", clientToken.getResourceIds());
            response.put("client_authorities", clientToken.getAuthorities());
        }
        return response;
    }

    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> response = new LinkedHashMap<String, Object>();
        if (authentication.getPrincipal() instanceof LoginUser) {
            LoginUser user = (LoginUser) authentication.getPrincipal();
            response.put("user_id", user.getId());
            response.put("user_authorities", authentication.getAuthorities());
        }
        return response;
    }
}
